package com.shike.hq.config;

import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import com.shike.hq.security.MyAuthenticationFailureHandler;
import com.shike.hq.security.VerificationCodeFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.Properties;

// 开启WebSecurity模式
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;
    /**
     * 定制请求的授权规则，页面所有人可以访问
     *
     * 匹配 "/","/login","/error 路径，不需要权限即可访问
     * 匹配 "/index" 及其以下所有路径，都需要 "USER" 权限(正在进行中)
     * 登录地址为 "/login"，登录成功默认跳转到页面 "/index"
     * 退出登录的地址为 "/logout"，退出成功后跳转到页面 "/loginPage"
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/static/**","/dist/**","/plugins/**","/captcha.jpg").permitAll()
                .antMatchers("/loginPage/**","/Captcha/**").permitAll()
//                .antMatchers("/index").permitAll()
                .antMatchers("/base/**").hasRole("ADMIN")
                .antMatchers("/label/**").hasRole("ADMIN")
//                .antMatchers("/base/**").permitAll()
//                .antMatchers("/label/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                // 登录页面
                .loginPage("/loginPage")
                // 登录接口:提交表单之后跳转的地址,可以看作一个中转站，这个步骤就是验证user的一个过程
                .loginProcessingUrl("/loginPage/login")
//                .successHandler(new MyAuthenticationProvider())
//                .usernameParameter("username").passwordParameter("password")
                // 登录后优先进入输入的地址页面
                .defaultSuccessUrl("/index")
                // 无论输入什么地址在登陆后都会直接进入index
//                .successForwardUrl("/index")
                .failureHandler(new MyAuthenticationFailureHandler())
//                .failureUrl("/loginPage")
                .and()
            .httpBasic()
                .and()
                // 关闭csrf功能，跨站请求伪造，默认只能通过post方式提交logout请求，
                // 否则可能因为这里验证导致无法使用自定义token访问数据，关闭跨站请求防护
                .csrf().disable()
                .logout().logoutUrl("/logout")
                .logoutSuccessUrl("/loginPage")
//                .and()
//                .rememberMe().rememberMeParameter("remember");
                .and()
            // 允许前端iframe内嵌页面
        .headers().frameOptions().disable()
                .and()
                .sessionManagement()
                .sessionFixation().newSession();
//                .maximumSessions(1);
        // 将过滤器添加在UsernamePasswordAuthenticationFilter之前
        http.addFilterBefore(new VerificationCodeFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 定义认证规则
     *
     * Spring security 5.0中新增了多种加密方式，也改变了密码的格式
     * 要想我们的项目还能够正常登陆，需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
     * spring security 官方推荐的是使用bcrypt加密方式
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //将用户信息加载到security
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        // 为了测试演示方便，暂时使用NoOpPasswordEncoder不加密
        return NoOpPasswordEncoder.getInstance();
    }

    // 配置验证码工具
    @Bean
    public Producer captcha(){
        // 配置凸显验证码的基本参数
        Properties properties = new Properties();
        // 图片宽度
        properties.setProperty("kaptcha.image.width","100");
        // 图片高度
        properties.setProperty("kaptcha.image.height","50");
        // 字符集
        properties.setProperty("kaptcha.textproducer.char.string","0123456789");
        // 字符长度
        properties.setProperty("kaptcha.textproducer.char.length","4");
        Config config = new Config(properties);
        // 使用默认的图形验证码实现，当然也可以自定义实现
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}
